/*
 * @Copyright: Copyright (c) 2030 吴周海
 * @Author: wzh200x@126.com
 * @Date: 2025-10-11 14:17:55
 * @LastEditors: wzh200x@126.com
 * @LastEditTime: 2025-10-11 14:29:30
 * @FilePath: \gogamewebserver\goGameWebServer\internal\jwt\jwt.go
 * @Description: 文件功能描述
 */
package jwt

import (
	"errors"
	"fmt"
	"goGameWebServer/internal/manager/cachemanager"
	"time"

	"github.com/golang-jwt/jwt/v5"
	"github.com/google/uuid"
)

// JWT声明结构
type Claims struct {
	UserID    uint   `json:"user_id"`
	Username  string `json:"username"`
	LoginUUID string `json:"login_uuid"` // 添加登录UUID字段，用于多端登录控制
	jwt.RegisteredClaims
}

// JWT密钥
var jwtSecret = []byte("webServer_secret_key")

// 使用middleware包中的Claims结构体

// 生成JWT令牌
func GenerateToken(userID uint, username string) (string, int64, error) {
	nowTime := time.Now()
	expireTime := nowTime.Add(24 * time.Hour) // 令牌有效期24小时
	expireTimeUnix := expireTime.Unix()       // 过期时间戳

	// 生成唯一的登录UUID
	loginUUID := uuid.New().String()

	claims := Claims{
		UserID:    userID,
		Username:  username,
		LoginUUID: loginUUID,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(expireTime),
			IssuedAt:  jwt.NewNumericDate(nowTime),
			Issuer:    "webServer",
		},
	}

	// 构建缓存键：auth:userID:loginUUID
	cacheKey := fmt.Sprintf("auth:%s:%d", username, userID)

	// 将用户信息序列化为字节数组
	userInfoBytes := []byte(loginUUID)

	// 设置缓存，过期时间与令牌相同
	cachemanager.ManagerCache().Put(cacheKey, userInfoBytes, 24*60*60)

	tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	token, err := tokenClaims.SignedString(jwtSecret)
	return token, expireTimeUnix, err
}

// 解析和验证JWT令牌
func ParseToken(token string) (*Claims, error) {
	tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return jwtSecret, nil
	})

	if err != nil {
		return nil, err
	}

	if tokenClaims != nil {
		if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
			return claims, nil
		}
	}

	return nil, errors.New("invalid token")
}

// 刷新JWT令牌
func RefreshToken(token string) (string, int64, error) {
	claims, err := ParseToken(token)
	if err != nil {
		return "", 0, err
	}

	// 检查令牌是否即将过期（例如，如果有效期小于12小时）
	if time.Until(time.Unix(claims.ExpiresAt.Unix(), 0)) > 12*time.Hour {
		// 令牌仍然有效，不需要刷新，返回原令牌和过期时间
		return token, claims.ExpiresAt.Unix(), nil
	}

	// 验证登录UUID是否在缓存中有效
	if claims.LoginUUID != "" {
		cacheKey := fmt.Sprintf("auth:%s:%d", claims.Username, claims.UserID)
		cacheResp, err := cachemanager.ManagerCache().Get(cacheKey)
		if err != nil {
			// 缓存中不存在该UUID，可能是已在其他设备登录或令牌已失效
			return "", 0, errors.New("登录已失效，请重新登录")
		}

		// 验证登录UUID是否匹配
		if claims.LoginUUID != string(cacheResp) {
			return "", 0, errors.New("登录已失效，请重新登录")
		}
	}

	// 生成新令牌，保留原有的UUID
	nowTime := time.Now()
	expireTime := nowTime.Add(24 * time.Hour) // 令牌有效期24小时
	expireTimeUnix := expireTime.Unix()       // 过期时间戳

	// 使用原有的UUID或生成新的UUID
	loginUUID := claims.LoginUUID
	if loginUUID == "" {
		loginUUID = uuid.New().String()
	}

	newClaims := Claims{
		UserID:    claims.UserID,
		Username:  claims.Username,
		LoginUUID: loginUUID,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(expireTime),
			IssuedAt:  jwt.NewNumericDate(nowTime),
			Issuer:    "webServer",
		},
	}

	// 构建缓存键：auth:userID:loginUUID
	cacheKey := fmt.Sprintf("auth:%s:%d", claims.Username, claims.UserID)

	// 将用户信息序列化为字节数组
	userInfoBytes := []byte(loginUUID)

	// 设置缓存，过期时间与令牌相同
	// cacheSetReq := cacheServerProtocol.CacheSetRequest{
	// 	Key:        cacheKey,
	// 	Value:      userInfoBytes,
	// 	Expiration: int64(24 * 60 * 60), // 24小时，单位秒
	// }

	cachemanager.ManagerCache().Put(cacheKey, userInfoBytes, 24*60*60)
	// if err != nil {
	// 	tars.GetLogger("").Errorf("Failed to set login UUID in cache during token refresh: %v", err)
	// 	// 即使缓存设置失败，仍然继续生成令牌
	// }

	tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, newClaims)
	newToken, err := tokenClaims.SignedString(jwtSecret)
	return newToken, expireTimeUnix, err
}
